﻿#pragma once
#include "SysApi.h"
//tcp socket 的简单封装
class TCPSocket
{
public:
	TCPSocket(int af)
	{
		m_socket=::socket(af, SOCK_STREAM, IPPROTO_TCP);
		if (m_socket==-1)
		{
			printf("error to create socket.");
		}
		bool reuseAddr=true;
		::setsockopt(m_socket,SOL_SOCKET,SO_REUSEADDR,(char*)&reuseAddr,sizeof(reuseAddr));
	}

	TCPSocket(SOCKET soc)
	{
		m_socket=soc;
		bool reuseAddr=true;
		::setsockopt(m_socket,SOL_SOCKET,SO_REUSEADDR,(char*)&reuseAddr,sizeof(reuseAddr));
	}

	~TCPSocket()
	{
		if(m_socket!=INVALID_SOCKET)
			closesocket(m_socket);
	}

	inline int Bind(const sockaddr* addr, int addrLen)
	{
		return ::bind(m_socket,addr, addrLen);
	}

	inline int Connect(const sockaddr* addr, int addrLen)
	{
		return ::connect(m_socket,addr, addrLen);
	}

	inline int Send(const void *buf, int len, int flag)
	{
		return ::send(m_socket,(const char*)buf,len, flag);
	}

	inline int Recv(void *buf, int len,int flag)
	{
		return ::recv(m_socket,(char*)buf,len,flag);
	}

	void Attach(SOCKET soc)
	{
		closesocket(m_socket);
		m_socket=soc;
	}

	SOCKET Detach()
	{
		SOCKET temp=m_socket;
		m_socket=INVALID_SOCKET;
		return temp;
	}

	int GetSockName(sockaddr* addr,int* addrLen)
	{
		int rslt=getsockname(m_socket,(sockaddr*)addr,addrLen);
		return rslt;
	}

	//检查是否可用读写
	bool Check(uint32_t time,bool* readable,bool* writeable)
	{
		//select超时检查socket
		fd_set fdRead;
		struct timeval timeout;
		timeout.tv_usec = time * 1000;
		timeout.tv_sec = 0;

		FD_ZERO(&fdRead);
		FD_SET(m_socket, &fdRead);


		if (writeable)
		{
			fd_set fdWrite;
			FD_ZERO(&fdWrite);
			FD_SET(m_socket, &fdWrite);

			int nRet = ::select(m_socket + 1, &fdRead, &fdWrite, NULL, &timeout);
			if (nRet>0)
			{
				if (FD_ISSET(m_socket, &fdRead))
					*readable = true;
				else
					*readable = false;

				if (FD_ISSET(m_socket, &fdWrite))
					*writeable = true;
				else
					*writeable = false;
				return true;
			}
			else
				return false;
		}
		else
		{
			int nRet = ::select(m_socket + 1, &fdRead, NULL, NULL, &timeout);
			if (nRet>0)
			{
				if (FD_ISSET(m_socket, &fdRead))
					*readable = true;
				else
					*readable = false;
				return true;
			}
			else
				return false;
		}

	}

	//设置为非阻塞模式
	void SetNonblocking()
	{
		unsigned long nonblocking = 1;
		ioctlsocket(m_socket, FIONBIO, (unsigned long*)&nonblocking);
	}

	SOCKET getSocket() { return m_socket; }
private:
	SOCKET   m_socket;
};


